package com.vrview.administrator.fresco;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;

import com.facebook.binaryresource.BinaryResource;
import com.facebook.binaryresource.FileBinaryResource;
import com.facebook.cache.common.CacheKey;
import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.common.disk.NoOpDiskTrimmableRegistry;
import com.facebook.common.internal.Supplier;
import com.facebook.common.memory.MemoryTrimType;
import com.facebook.common.memory.MemoryTrimmable;
import com.facebook.common.memory.NoOpMemoryTrimmableRegistry;
import com.facebook.common.util.ByteConstants;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory;
import com.facebook.imagepipeline.cache.MemoryCacheParams;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.core.ImagePipelineFactory;
import com.facebook.imagepipeline.decoder.ProgressiveJpegConfig;
import com.facebook.imagepipeline.image.ImmutableQualityInfo;
import com.facebook.imagepipeline.image.QualityInfo;
import com.facebook.imagepipeline.listener.RequestListener;
import com.facebook.imagepipeline.listener.RequestLoggingListener;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.Set;

import okhttp3.OkHttpClient;

/**
 * Fresco图片缓存设置
 * <p>QLH on 2016/10/18 17:35</p>
 */
public class ImagePipelineConfigFactory {

    //分配的可用内存
    private static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
    //使用缓存大小
    private static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 4;
    //小图极低磁盘空间缓存的最大值（特性：可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图）
    private static final int MAX_SMALL_DISK_VERYLOW_CACHE_SIZE = 20 * ByteConstants.MB;
    //小图低磁盘空间缓存的最大值（特性：可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图）
    private static final int MAX_SMALL_DISK_LOW_CACHE_SIZE = 60 * ByteConstants.MB;
    //默认图极低磁盘空间缓存的最大值
    private static final int MAX_DISK_CACHE_VERYLOW_SIZE = 20 * ByteConstants.MB;
    //默认图低磁盘空间缓存的最大值
    private static final int MAX_DISK_CACHE_LOW_SIZE = 60 * ByteConstants.MB;
    //默认图磁盘缓存的最大值
    private static final int MAX_DISK_CACHE_SIZE = 100 * ByteConstants.MB;
    //小图所放路径的文件夹名
    private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "ImagePipelineCacheSmall";
    //默认图所放路径的文件夹名
    private static final String IMAGE_PIPELINE_CHCHE_DIR = "ImagePipelineCacheDefault";
    //默认Android配置
    private static ImagePipelineConfig mImagePipelineConfig;
    //使用okhttp配置
    private static ImagePipelineConfig mOkhttpImagePipelineConfig;
    //缓存大小的单位
    public static final String TYPE_KB = "KB";
    public static final String TYPE_MB = "MB";
    public static final String TYPE_GB = "GB";

//----------------------------对外方法--------------------------------------------

    /**
     * 使用Android自带的网络加载图片
     *
     * @param context
     */
    public static ImagePipelineConfig getImagePipelineConfig(Context context) {
        if (mImagePipelineConfig == null) {
            ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(context);
            configureCaches(configBuilder, context);
            configureLoggingListeners(configBuilder);
            configureOptions(configBuilder);
            mImagePipelineConfig = configBuilder.build();
        }

        return mImagePipelineConfig;
    }

    /**
     * 使用OkHttp网络库加载图片
     *
     * @param context
     */
    public static ImagePipelineConfig getOkHttpImagePipelineConfig(Context context) {
        if (mOkhttpImagePipelineConfig == null) {
            OkHttpClient okHttpClient = new OkHttpClient();
            ImagePipelineConfig.Builder configBuilder =
                    OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
            configureCaches(configBuilder, context);
            configureLoggingListeners(configBuilder);
            mOkhttpImagePipelineConfig = configBuilder.build();
        }
        return mOkhttpImagePipelineConfig;
    }

    /**
     * 根据Url获取缓存中的某个图片
     *
     * @param url
     */
    public static Bitmap getBitmapFromCacheUseUrl(String url) {

        return getBitmapFromCache(url);
    }

    /**
     * 获取Fresco缓存大小
     *
     * @param type 单位（KB MB GB）
     */
    public static String getMainDiskCacheSizeFromMobilePhon(String type) {

        return getMainDiskCacheSize(type);
    }

    /**
     * 清理Fresco的缓存
     */
    public static void cleanCacheFromMobilePhon() {

        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        imagePipeline.clearCaches();

    }

    /**
     * 清理Fresco的内存缓存
     */
    public static void cleanMemoryCacheFromMobilePhon() {

        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        imagePipeline.clearMemoryCaches();

    }

    /**
     * 清理Fresco的SD卡缓存
     */
    public static void cleanDiskCacheFromMobilePhon() {

        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        imagePipeline.clearDiskCaches();

    }

    //---------------------私有方法---------------------------------------------------------------

    /**
     * 配置内存缓存和磁盘缓存
     */
    private static void configureCaches(ImagePipelineConfig.Builder configBuilder, Context context) {
        //内存配置
        final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams(
                MAX_MEMORY_CACHE_SIZE,// 内存缓存中总图片的最大大小,以字节为单位。
                Integer.MAX_VALUE, // 内存缓存中图片的最大数量。
                MAX_MEMORY_CACHE_SIZE,// 内存缓存中准备清除但尚未被删除的总图片的最大大小,以字节为单位。
                Integer.MAX_VALUE, // 内存缓存中准备清除的总图片的最大数量。
                Integer.MAX_VALUE  // 内存缓存中单个图片的最大大小。
        );

        //修改内存图片缓存数量，空间策略（这个方式有点恶心）
        Supplier<MemoryCacheParams> mSupplierMemoryCacheParams = new Supplier<MemoryCacheParams>() {
            @Override
            public MemoryCacheParams get() {
                return bitmapCacheParams;
            }
        };
        //小图片的磁盘配置
        DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder(context)
                .setBaseDirectoryPath(context.getApplicationContext().getCacheDir())//缓存图片基路径
                .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)//文件名
                .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的大小
                .setMaxCacheSizeOnLowDiskSpace(MAX_SMALL_DISK_LOW_CACHE_SIZE)//缓存的最大大小，低磁盘空间
                .setMaxCacheSizeOnVeryLowDiskSpace(MAX_SMALL_DISK_VERYLOW_CACHE_SIZE)//缓存的最大大小，极低磁盘空间
                .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                .build();

        //默认图片的磁盘配置
        DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(context)
                .setBaseDirectoryPath(Environment.getExternalStorageDirectory().getAbsoluteFile())//本地缓存目录，记得开启权限
                .setBaseDirectoryName(IMAGE_PIPELINE_CHCHE_DIR)//缓存文件名
                .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的大小
                .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_CACHE_LOW_SIZE)//缓存的最大大小，低磁盘空间
                .setMaxCacheSizeOnVeryLowDiskSpace(MAX_DISK_CACHE_VERYLOW_SIZE)//缓存的最大大小，极低磁盘空间
                .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                .build();
        //缓存图片配置
        configBuilder
                .setProgressiveJpegConfig(mProgressiveJpegConfig)
                .setBitmapsConfig(Bitmap.Config.ARGB_4444)
                .setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams)
                .setSmallImageDiskCacheConfig(diskSmallCacheConfig)
                .setMainDiskCacheConfig(diskCacheConfig)
                .setMemoryTrimmableRegistry(NoOpMemoryTrimmableRegistry.getInstance())
                .setResizeAndRotateEnabledForNetwork(true);
        //清理缓存

    }

    private static void configureLoggingListeners(ImagePipelineConfig.Builder configBuilder) {
        Set<RequestListener> requestListeners = new HashSet<>();
        requestListeners.add(new RequestLoggingListener());
        configBuilder.setRequestListeners(requestListeners);
    }

    private static void configureOptions(ImagePipelineConfig.Builder configBuilder) {
        configBuilder.setDownsampleEnabled(true);
    }

    private static Bitmap getBitmapFromCache(String url) {

        ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)).build();

        CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(imageRequest, null);
        BinaryResource resource = ImagePipelineFactory.getInstance()
                .getMainDiskStorageCache().getResource(cacheKey);
        final File file = ((FileBinaryResource) resource).getFile();
        Bitmap bitmap = null;
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            bitmap = BitmapFactory.decodeStream(fileInputStream);
            //URI uri = file.toURI();
            //Log.i("bitmap",bitmap.getWidth()+"---"+bitmap.getHeight()+"---"+uri.getPath());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                    fileInputStream = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return bitmap;
    }

    private static String getMainDiskCacheSize(String type) {

        String size = "";
        DecimalFormat df = new DecimalFormat("#.0");//格式化数据
        long cacheSize = Fresco.getImagePipelineFactory().getMainDiskStorageCache().getSize();
        if (type.equals(TYPE_KB)) {
            size = df.format(cacheSize / 1024);
        } else if (type.equals(TYPE_MB)) {
            size = df.format(cacheSize / 1024 / 1024);
        } else if (type.equals(TYPE_GB)) {
            size = df.format(cacheSize / 1024 / 1024 / 1024);
        }

        if (Integer.valueOf(size) == 0) {
            size = "0";
        }

        return size;
    }

    //渐进式图片
    private static ProgressiveJpegConfig mProgressiveJpegConfig = new ProgressiveJpegConfig() {
        @Override
        public int getNextScanNumberToDecode(int scanNumber) {
            return scanNumber + 2;
        }

        @Override
        public QualityInfo getQualityInfo(int scanNumber) {
            boolean isGoodEnough = (scanNumber >= 5);
            return ImmutableQualityInfo.of(scanNumber, isGoodEnough, false);
        }
    };


}
